home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2005 March / Macworld CD March 2005 - Marathon Trilogy.iso / Shareware World / Text Processing / HexEdit Release.sit / HexEdit Release / Project / Source / HexCompare.c < prev    next >
Encoding:
C/C++ Source or Header  |  2004-10-31  |  14.5 KB  |  577 lines  |  [TEXT/CWIE]

  1. /*
  2.  * The contents of this file are subject to the Mozilla Public
  3.  * License Version 1.1 (the "License"); you may not use this file
  4.  * except in compliance with the License. You may obtain a copy of
  5.  * the License at http://www.mozilla.org/MPL/
  6.  * 
  7.  * Software distributed under the License is distributed on an "AS
  8.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  9.  * implied. See the License for the specific language governing
  10.  * rights and limitations under the License.
  11.  * 
  12.  * The Original Code is Copyright 1993 Jim Bumgardner.
  13.  * 
  14.  * The Initial Developer of the Original Code is Jim Bumgardner
  15.  * Portions created by Lane Roathe are
  16.  * Copyright (C) Copyright © 1996-2002.
  17.  * All Rights Reserved.
  18.  *
  19.  * Modified: $Date: 2004/09/09 00:23:30 $
  20.  * Revision: $Id: HexCompare.c,v 1.21 2004/09/09 00:23:30 raving Exp $
  21.  *
  22.  * Contributor(s):
  23.  *        Lane Roathe
  24.  *        Nick Shanks
  25.  *        Nick Pissaro Jr. (NP)
  26.  */
  27.  
  28. // 05/10/01 - GAB: MPW environment support
  29. #ifdef __MPW__
  30. #include "MPWIncludes.h"
  31. #endif
  32.  
  33. #include "HexCompare.h"
  34. #include "EditRoutines.h"
  35. #include "EditScrollbar.h"
  36. #include "Main.h"
  37. #include "Prefs.h"
  38. #include "Utility.h"
  39.  
  40. // variables
  41. //LR 180 extern short CompareFlag;
  42. extern unsigned char    gSearchBuffer[256];
  43.  
  44. WindowRef        CompWind1 = NULL,
  45.                 CompWind2 = NULL;
  46. Boolean            WeFoundWind1 = false,
  47.                 WeFoundWind2 = false;
  48.  
  49. /*** PERFORM TEXT COMPARE ***/
  50. //LR 185 -- this one routine now performs EITHER match or diff comparisons...and WAY faster :)
  51. Boolean PerformTextCompare( EditWindowPtr dWin1, EditWindowPtr dWin2 )
  52. {
  53. //    returns differences in data of two edit windows
  54.     Byte        ch1, ch2;
  55.     short        matchIdx, matchCnt;
  56.     long        addr1, addr2, matchAddr1 = 0, matchAddr2 = 0, adjust;
  57.     register     EditChunk **c1, **c2;
  58.  
  59.     MySetCursor( C_Watch );
  60.  
  61.     // Search in Direction gPrefs.searchForward for text gSearchBuffer
  62.  
  63.     addr1 = dWin1->startSel;
  64.     addr2 = dWin2->startSel;
  65.  
  66.     if( gPrefs.searchForward )
  67.         adjust = 1;
  68.     else
  69.         adjust = -1;
  70.     
  71.     // 1 = byte, 2 = words, 4 = longs, ect...
  72.     matchCnt = gPrefs.searchSize;
  73.  
  74.     //LR 185 -- we handle the chucks ourself to speed up searching!
  75.     //            get the chunk for the current address & load it.
  76.  
  77.     c1 = GetChunkByAddr( dWin1, addr1 );
  78.     c2 = GetChunkByAddr( dWin2, addr2 );
  79.     if( !c1 || !c2 )
  80.         goto Failure;    // should never happen, but...
  81.  
  82.     LoadChunk( dWin1, c1 );
  83.     LoadChunk( dWin2, c2 );
  84.  
  85.     matchIdx = 0;
  86.     addr1 += adjust;
  87.     addr2 += adjust;
  88.  
  89.     //LR 185 -- re-write of compare loop; it was pathetically slow, etc.
  90.     while( addr1 >= 0 && addr1 < dWin1->fileSize && addr2 >= 0 && addr2 < dWin2->fileSize )
  91.     {
  92.         if( !(addr1 % 4096) )        //LR 1.72 -- don't slow our searches down unnecessarily!
  93.         {
  94.             if( CheckForAbort() )    //LR: 1.66 - allow user to abort the search
  95.                 break;
  96.         }
  97.  
  98. //185        ch1 = GetByte( dWin1, addr1 );
  99. //185        ch2 = GetByte( dWin2, addr2 );
  100.         ch1 = (Byte) (*(*c1)->data)[addr1 - (*c1)->addr];
  101.         ch2 = (Byte) (*(*c2)->data)[addr2 - (*c2)->addr];
  102.         if( (gPrefs.searchType == CM_Different && ch1 != ch2) || (gPrefs.searchType == CM_Match && ch1 == ch2) )
  103.         {
  104.             if( matchIdx == 0 )
  105.             {
  106.                 matchAddr1 = addr1;
  107.                 matchAddr2 = addr2;
  108.             }
  109.             ++matchIdx;
  110.  
  111.             if( matchIdx >= matchCnt )
  112.                 goto Success;
  113.  
  114.             ++addr1;
  115.             ++addr2;
  116.             if( addr1 == dWin1->fileSize )
  117.             {
  118.                 matchIdx = 0;
  119.                 addr1 = matchAddr1;
  120.                 addr2 = matchAddr2;
  121.             }
  122.             else
  123.                 continue;
  124.         }
  125.         else if( matchIdx )    // if we were in a match, back it out!
  126.         {
  127.             matchIdx = 0;
  128.             addr1 = matchAddr1;
  129.             addr2 = matchAddr2;
  130.         }
  131.         addr1 += adjust;
  132.         addr2 += adjust;
  133.  
  134.         //LR 185 -- OK, here we must handle moving to a new chunk if outside current one
  135.         if( addr1 < (*c1)->addr )
  136.         {
  137.             UnloadChunk( dWin1, c1, true );
  138.             c1 = (*c1)->prev;
  139.             goto nc1;
  140.         }
  141.         else if( addr1 >= (*c1)->addr + (*c1)->size )
  142.         {
  143.             UnloadChunk( dWin1, c1, true );
  144.             c1 = (*c1)->next;
  145. nc1:
  146.             if( !c1 )
  147.                 goto Failure;
  148.  
  149.             LoadChunk( dWin1, c1 );    // no check, most likely not loaded, and checked in routine anyway
  150.         }
  151.  
  152.         if( addr2 < (*c2)->addr )
  153.         {
  154.             UnloadChunk( dWin2, c2, true );
  155.             c2 = (*c2)->prev;
  156.             goto nc2;
  157.         }
  158.         else if( addr2 >= (*c2)->addr + (*c2)->size )
  159.         {
  160.             UnloadChunk( dWin2, c2, true );
  161.             c2 = (*c2)->next;
  162. nc2:
  163.             if( !c2 )
  164.                 goto Failure;
  165.  
  166.             LoadChunk( dWin2, c2 );    // no check, most likely not loaded, and checked in routine anyway
  167.         }
  168.     }
  169.  
  170. Failure:
  171.     SysBeep( 1 );
  172.     MySetCursor( C_Arrow );
  173.     return false;
  174.  
  175. Success:
  176.     SelectWindow( dWin1->oWin.theWin );
  177.     dWin1->startSel = matchAddr1;
  178.     dWin1->endSel = dWin1->startSel + gPrefs.searchSize;
  179.     ScrollToSelection( dWin1, dWin1->startSel, true );
  180.  
  181.     SelectWindow( dWin2->oWin.theWin );
  182.     dWin2->startSel = matchAddr2;
  183.     dWin2->endSel = dWin2->startSel + gPrefs.searchSize;
  184.     ScrollToSelection( dWin2, dWin2->startSel, true );
  185.  
  186.     MySetCursor( C_Arrow );
  187.     return true;
  188. }
  189.  
  190. /*** PERFORM TEXT MATCH COMPARE ***/
  191. /*185
  192. Boolean PerformTextMatchCompare( EditWindowPtr dWin, EditWindowPtr dWin2 )
  193. {
  194. //    returns matches in data of two edit windows
  195.     Byte        ch, ch2;
  196.     short            matchIdx, matchCnt;
  197.     long        addr, addr2, matchAddr;
  198.  
  199.     MySetCursor( C_Watch );
  200.  
  201.     // Search in Direction gPrefs.searchForward
  202.     // for text gSearchBuffer
  203.  
  204.     if( gPrefs.searchForward )
  205.     {
  206.         addr = dWin->endSel;
  207.         addr2 = dWin2->endSel;
  208.     }
  209.     else
  210.     {
  211.         addr = dWin->startSel - 1;
  212.         addr2 = dWin2->startSel - 1;
  213.         if( addr < 0 )    return false;
  214.         if( addr2 < 0 )    return false;
  215.     }
  216.     
  217.     // 1 = byte, 2 = words, 4 = longs, ect...
  218.     matchCnt=gPrefs.searchSize+1;
  219.     if( gPrefs.searchSize==CM_Long ) matchCnt += 1;
  220.  
  221.     matchIdx = 0;
  222.     while ( !CheckForAbort() )        // LR: 1.7 -- allow aborting compares!
  223.     {
  224.         ch = GetByte( dWin, addr );
  225.         ch2 = GetByte( dWin2, addr2 );
  226.         if( ch == ch2 )
  227.         {
  228.             if( matchIdx == 0 ) matchAddr = addr;
  229.             ++matchIdx;
  230.             if( matchIdx >= matchCnt )
  231.                 goto Success;
  232.             ++addr;
  233.             ++addr2;
  234.             if( addr == dWin->fileSize )
  235.             {
  236.                 matchIdx = 0;
  237.                 addr = matchAddr;
  238.             }
  239.             else
  240.                 continue;
  241.         }
  242.         else
  243.         {
  244.             if( matchIdx ) {
  245.                 matchIdx = 0;
  246.                 addr = matchAddr;
  247.             }
  248.         }
  249.         if( gPrefs.searchForward )
  250.         {
  251.             ++addr;
  252.             ++addr2;
  253.             if( addr2 == dWin2->fileSize )
  254.                 goto Failure;
  255.             if( addr == dWin->fileSize )
  256.                 goto Failure;
  257.         }
  258.         else
  259.         {
  260.             --addr;
  261.             --addr2;
  262.             if( addr < 0 )
  263.                 goto Failure;
  264.             if( addr2 < 0 )
  265.                 goto Failure;
  266.         }
  267.     }
  268.  
  269. Failure:
  270.     SysBeep( 1 );
  271.     MySetCursor( C_Arrow );
  272.     return false;
  273.  
  274. Success:
  275.     SelectWindow( dWin->oWin.theWin );
  276.     dWin->startSel = matchAddr;
  277.     dWin->endSel = dWin->startSel + gPrefs.searchSize + 1;
  278.     if( gPrefs.searchSize==CM_Long ) dWin->endSel += 1;
  279.     ScrollToSelection( dWin, dWin->startSel, true );
  280.  
  281.     SelectWindow( dWin2->oWin.theWin );
  282.     dWin2->startSel = matchAddr;
  283.     dWin2->endSel = dWin2->startSel + gPrefs.searchSize + 1;
  284.     if( gPrefs.searchSize==CM_Long ) dWin2->endSel += 1;
  285.     ScrollToSelection( dWin2, dWin2->startSel, true );
  286.  
  287.     MySetCursor( C_Arrow );
  288.     return true;
  289. }
  290. */
  291.  
  292. /*** DO COMPARISON ***/
  293. void DoComparison( void )
  294. {
  295.     GrafPtr        oldPort;
  296.     
  297.     WindowRef    theWin;
  298.     
  299.     DialogPtr    pDlg;
  300. // LR: v1.6.5    Handle         iHandle;
  301. // LR: v1.6.5    Rect         iRect;
  302.     short iType, oldDir = gPrefs.searchForward;
  303.     EventRecord    theEvent;
  304.  
  305.     // put up dialog and let user shorteract
  306.  
  307.     GetPort( &oldPort );
  308.  
  309.     pDlg = GetNewDialog ( dlgCompare, 0L, kFirstWindowOfClass );
  310.  
  311.     MoveWindow( GetDialogWindow( pDlg ), 22, g.maxHeight -64 +8, true );
  312. //LR 1.73    SetPort( (GrafPtr)GetDialogPort( pDlg ) );
  313.     SetPortDialogPort( pDlg );
  314.  
  315.     SetDialogDefaultItem( pDlg, 1 );    // LR: v1.6.5 LR -- correct way of showing default button
  316. /*
  317.     GetDialogItem ( pDlg, 1, &iType, &iHandle, &iRect );    // ring around OK
  318.     PenSize( 3, 3 );
  319.     InsetRect( &iRect, -4, -4 );
  320.     FrameRoundRect( &iRect, 16, 16 );
  321. */
  322. //LR 180    DrawPage( (EditWindowPtr) GetWRefCon( CompWind1 ) );
  323.     UpdateOnscreen( CompWind1 );
  324. //LR 180    DrawPage( (EditWindowPtr) GetWRefCon( CompWind2 ) );
  325.     UpdateOnscreen( CompWind2 );
  326.             
  327.     // show the contents of the windows
  328.     ShowWindow( GetDialogWindow( pDlg ) );
  329.     DrawDialog( pDlg );
  330.  
  331.     // handle event processing
  332.     do
  333.     {
  334.         theWin = NULL;
  335.         WaitNextEvent( everyEvent, &theEvent, 10L, NULL );
  336.  
  337.         if( !CompWind1 || !CompWind2 )    //1.73 LR :exit if user closes one of the windows!
  338.             iType = 4;
  339.         else
  340.             iType = 0;
  341.  
  342.         // If the click is in the dialog window, make sure it always processes the click, regardless
  343.         // of whether it is on top or not.--NPJr.
  344.         if( theEvent.what == mouseDown )
  345.             FindWindow( theEvent.where, &theWin );
  346.         
  347.         if ( GetDialogWindow( pDlg ) == theWin || IsDialogEvent( &theEvent ) )
  348.         {
  349.             if( theWin != FrontNonFloatingWindow() )
  350.                 SelectWindow( theWin );
  351.             
  352.             DialogSelect( &theEvent, &pDlg, &iType );
  353.         
  354.             if( iType==1 )            // handle find forward here
  355.             {
  356.                 gPrefs.searchForward = true;
  357.                 PerformTextCompare( (EditWindowPtr) GetWRefCon( CompWind1 ), (EditWindowPtr) GetWRefCon( CompWind2 ) );
  358.  
  359. /*185                if( gPrefs.searchType == CM_Match )
  360.                     PerformTextMatchCompare( (EditWindowPtr) GetWRefCon( CompWind1 ), (EditWindowPtr) GetWRefCon( CompWind2 ) );
  361.                 else
  362.                     PerformTextDifferenceCompare( (EditWindowPtr) GetWRefCon( CompWind1 ), (EditWindowPtr) GetWRefCon( CompWind2 ) );
  363. */
  364.                 SelectWindow( (WindowRef)pDlg );
  365.             }
  366.             if( iType==3 )            // handle find backward here
  367.             {
  368.                 gPrefs.searchForward = false;
  369.                 PerformTextCompare( (EditWindowPtr) GetWRefCon( CompWind1 ), (EditWindowPtr) GetWRefCon( CompWind2 ) );
  370.  
  371. /*185                if( gPrefs.searchType == CM_Match )
  372.                     PerformTextMatchCompare( (EditWindowPtr) GetWRefCon( CompWind1 ), (EditWindowPtr) GetWRefCon( CompWind2 ) );
  373.                 else
  374.                     PerformTextDifferenceCompare( (EditWindowPtr) GetWRefCon( CompWind1 ), (EditWindowPtr) GetWRefCon( CompWind2 ) );
  375. */
  376.                 SelectWindow( (WindowRef)pDlg );
  377.             }
  378.         }
  379.         else
  380.             DoEvent( &theEvent );
  381.  
  382.     } while (!g.quitFlag && (iType != 2) && (iType != 4));    // 2 = Done, 4 = Drop out and edit
  383.             
  384.     // Close dialog
  385.     DisposeDialog( pDlg );
  386.     SetPort( oldPort );
  387.  
  388.     if( iType == 2 )
  389.     {
  390.         if( CompWind1 && ! WeFoundWind1 )
  391.             CloseEditWindow( CompWind1 );        // close windows (1.7 vs disposing them!) if done ( ie, not editing )
  392.         if( CompWind2 && ! WeFoundWind2 )
  393.             CloseEditWindow( CompWind2 );
  394.     }
  395.  
  396.     CompWind1 = CompWind2 = NULL;
  397.     WeFoundWind1 = WeFoundWind2 = false;
  398.     gPrefs.searchForward = oldDir;
  399. }
  400.  
  401. /**** GET COMPARE FILES ***/
  402. //LR 180 -- pass in modifiers so we can see if we want to force file selection dialogs
  403.  
  404. Boolean GetCompareFiles( short modifiers )
  405. {
  406. //    main handler for the compare of the contents of two windows
  407. //LR 180    short         iType;
  408.     EditWindowPtr ew1, ew2;
  409.  
  410.     // close previous file compare windows if open
  411.  
  412.     // NP 177 -- if windows are open use them instead of asking.
  413.     // LR 180 -- if 'Option' pressed then we do it the old-fashion way :)
  414.  
  415.     if( modifiers & optionKey )
  416.     {    
  417.         if( CompWind1 )    DisposeEditWindow( CompWind1 );
  418.         if( CompWind2 )    DisposeEditWindow( CompWind2 );
  419.     }
  420.     else    // NP 177 -- See if there are windows we can use already. Rearrange them for doing the comparison.
  421.     {
  422.         CompWind1 = CompWind2 = NULL;
  423.         WeFoundWind1 = WeFoundWind2 = false;
  424.         
  425.         ew1 = FindFirstEditWindow();            // look for 1st window
  426.         if( ew1 )
  427.         {
  428.             CompWind1 = ew1->oWin.theWin;
  429.             WeFoundWind1 = true;                // We found it, we shouldn't destroy it.
  430.             SizeEditWindow( CompWind1, kWindowCompareTop );
  431.  
  432.             ew2 = FindNextEditWindow( ew1 );    // look for 2nd window
  433.             if( ew2 )
  434.             {
  435.                 CompWind2 = ew2->oWin.theWin;
  436.                 WeFoundWind2 = true;
  437.                 SizeEditWindow( CompWind2, kWindowCompareBtm );
  438.             }
  439.         }
  440.     }
  441.  
  442.     // NP 177 -- Open files for comparing if we did not find windows to start with.
  443.     
  444.     if( ! CompWind1 )
  445.     {
  446. //LR 180        CompareFlag=1;
  447.         if( -1 == AskEditWindow( kWindowCompareTop ) )
  448.         {
  449. //LR 180            CompareFlag = 0;
  450.             return false;        // if Cancel, exit
  451.         }
  452.     }
  453.     
  454.     if( ! CompWind2 )
  455.     {
  456. //LR 180        CompareFlag=2;
  457.         if( -1 == AskEditWindow( kWindowCompareBtm ) )
  458.             goto compexit;
  459.     }
  460.  
  461.     if( CompWind1 == CompWind2 || !CompWind1 || !CompWind2 )    //LR 180 -- if same window we compare to an open file
  462.         goto compexit;
  463.  
  464.     ew1 = (EditWindowPtr)GetWRefCon( CompWind1 );
  465.     ew2 = (EditWindowPtr)GetWRefCon( CompWind2 );
  466.  
  467.     // LR: v1.6.5 don't allow comparing a file to itself!
  468.     if( ew1 && ew2    && (ew1->fsSpec.vRefNum == ew2->fsSpec.vRefNum)
  469.                     && (ew1->fsSpec.parID == ew2->fsSpec.parID)
  470.                     && !MacCompareString( ew1->fsSpec.name, ew2->fsSpec.name, NULL ) )
  471.     {
  472. compexit:
  473.         if( CompWind1 && ! WeFoundWind1 )
  474.             CloseEditWindow( CompWind1 );        // close windows (1.7 vs disposing them!) if done ( ie, not editing )
  475.         if( CompWind2 && ! WeFoundWind2 )
  476.             CloseEditWindow( CompWind2 );
  477.         
  478.         CompWind1 = CompWind2 = NULL;
  479.         WeFoundWind1 = WeFoundWind2 = false;
  480. //LR 180        CompareFlag = 0;
  481.  
  482.         return false;
  483.     }
  484.  
  485. //LR 180    CompareFlag = 0;
  486.     return true;
  487. }
  488.  
  489. /*** COMPARISON PREFERENCES ***/
  490. void ComparisonPreferences( void )
  491. {
  492. //    handler for the options dialog for compare.
  493.     GrafPtr        oldPort;
  494.     DialogPtr    pDlg;
  495. // LR: v1.6.5    Handle         iHandle;
  496.     short         iType, radio1, radio2;
  497. // LR: v1.6.5    Rect         iRect;
  498.  
  499.     GetPort( &oldPort );
  500.     // make dialog
  501.     pDlg = GetNewDialog ( dlgComparePref, 0L, kFirstWindowOfClass );
  502.  
  503.     SetPortDialogPort( pDlg );
  504.  
  505.     radio1 = gPrefs.searchSize;
  506.     radio2 = gPrefs.searchType;
  507.  
  508.     // init radio buttons to current settings...
  509.     SetControl( pDlg, CP_Bytes, gPrefs.searchSize == CM_Byte );
  510.     SetControl( pDlg, CP_Words, gPrefs.searchSize == CM_Word );
  511.     SetControl( pDlg, CP_Longs, gPrefs.searchSize == CM_Long );
  512.     SetControl( pDlg, CP_Different, gPrefs.searchType == CM_Different );
  513.     SetControl( pDlg, CP_Match, gPrefs.searchType == CM_Match );
  514.     SetControl( pDlg, CP_Case, gPrefs.searchCase );
  515.  
  516.     SetDialogDefaultItem( pDlg, CP_Done );    // LR: v1.6.5 LR -- correct way of showing default button
  517.  
  518.     ShowWindow( GetDialogWindow( pDlg ) );    // LR 1.73 -- dialog now hidden at first launch!
  519.  
  520.     // handle event processing
  521.     do
  522.     {
  523.         ModalDialog( NULL, &iType );
  524.         switch ( iType )
  525.         {
  526.             // handle each radio button...
  527.             case CP_Bytes:
  528.                 radio1 = CM_Byte;
  529.                 SetControl( pDlg, CP_Bytes, 1 );
  530.                 SetControl( pDlg, CP_Words, 0 );
  531.                 SetControl( pDlg, CP_Longs, 0 );
  532.                 break;
  533.             
  534.             case CP_Words:
  535.                 radio1 = CM_Word;
  536.                 SetControl( pDlg, CP_Bytes, 0 );
  537.                 SetControl( pDlg, CP_Words, 1 );
  538.                 SetControl( pDlg, CP_Longs, 0 );
  539.                 break;
  540.             
  541.             case CP_Longs:
  542.                 radio1 = CM_Long;
  543.                 SetControl( pDlg, CP_Bytes, 0 );
  544.                 SetControl( pDlg, CP_Words, 0 );
  545.                 SetControl( pDlg, CP_Longs, 1 );
  546.                 break;
  547.                 
  548.             case CP_Different:
  549.                 radio2 = CM_Different;
  550.                 SetControl( pDlg, CP_Different, 1 );
  551.                 SetControl( pDlg, CP_Match, 0 );
  552.                 break;
  553.             
  554.             case CP_Match:
  555.                 radio2 = CM_Match;
  556.                 SetControl( pDlg, CP_Different, 0 );
  557.                 SetControl( pDlg, CP_Match, 1 );
  558.                 break;
  559.  
  560.             case CP_Case:
  561.                 gPrefs.searchCase ^= 1;
  562.                 SetControl( pDlg, CP_Case, gPrefs.searchCase );
  563.                 break;
  564.         }
  565.     } while( ( iType != CP_Done ) && ( iType != CP_Cancel ) );
  566.     
  567.     if( iType==CP_Done )
  568.     {
  569.         // change flags based on which one is selected
  570.         gPrefs.searchSize = radio1;
  571.         gPrefs.searchType = radio2;
  572.     }        
  573.     // close theWin
  574.     DisposeDialog( pDlg );
  575.     SetPort( oldPort );
  576. }
  577.